package ihm.actions.files;

import ihm.controllers.ATKcontroller;
import ihm.models.ATKmodel;
import ihm.views.options.ATKjOptionPane;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import characters.Characters;
import equipments.Equipment;
import equipments.Items;
import equipments.enumeration.AccessoriesSlots;
import equipments.enumeration.ArmorSlots;
import equipments.enumeration.EquipmentSlots;
import equipments.enumeration.HandsSlots;

import systems.exceptions.equipments.CanNotEquipThisItem;
import systems.languages.MultiLanguages;
import systems.rpgBuilder.RpgBuilder;

public class SaveLoadAction {  

  private static JFileChooser chooser;

  public static void Save(ATKcontroller controller) throws IOException
  {
    System.out.println("[SaveLoad] - Save Debut");

    ATKmodel model = controller.getModel();
    String fullPath = model.getFilePath() + model.getFileName();

    if(model.getFilePath() == null || model.getFileName() == null)
      fullPath="";

    System.out.println("FullPath : "+fullPath);
    //If it's a real save then the full path must be know...
    if(!fullPath.isEmpty())
    {
      File file = new  File(fullPath);
      saveIt(file, model.getCharacter());
    }else{
      //... Else it's a SaveAs action
      SaveAs(controller);
    }
    controller.getModel().setDirty(false);
    System.out.println("[SaveLoad] - Save Fin");
  }

  public static void SaveAs(ATKcontroller controller) throws IOException
  {
    System.out.println("[SaveLoad] - SaveAs Debut");
    boolean complete = false;
    int returnVal;
    File file;
    setChooserForSaveAs();
    do{
      returnVal = chooser.showSaveDialog(null);
      /*
       * Return val :
       * 0 - Save
       * 1 - Cancel/Closex
       */
      if(returnVal == 1)
        return;//do nothing and quit
      file = chooser.getSelectedFile();
      //Check if the file choosen contains the ATK extension
      file = checkExtension(file, controller);

      //If the file already exist ... 
      if(file.exists())
        //...we ask to ovewrite the file
        complete = askOverwrite(file);
      else
        complete = true;
    }while(!complete);
    saveIt(file, controller.getModel().getCharacter());
    controller.getModel().setDirty(false);
    controller.getModel().setFileName(file.getName());
    controller.getModel().setFilePath(file.getPath());
    System.out.println("[SaveLoad] - SaveAs Fin");
  }

  private static File checkExtension(File file, ATKcontroller controller) {
    System.out.println("[SaveLoad] - CheckExtension Debut");
    String filePath = file.getAbsolutePath();
    String fileName = file.getName();
    if(!fileName.matches("[\\w]+(\\.atk)"))
    { 
      System.out.println("[SaveLoad] - CheckExtension Extension Invalide.");
      fileName += ".atk";
      controller.getModel().setFileName(fileName);
      return new File(filePath+".atk");
    } 
    System.out.println("[SaveLoad] - CheckExtension Fin");
    return file;
  }

  private static void setChooserForSaveAs()
  {
    System.out.println("[SaveLoad] - setChooserForSaveAs Debut");
    chooser = new JFileChooser();
    chooser.setMultiSelectionEnabled(false);
    chooser.setDialogType(JFileChooser.SAVE_DIALOG);
    ATKfileFilter filter = new ATKfileFilter();
    filter.addSuffixe(".atk");
    filter.setDescription("dialog.fileFormat.text");
    chooser.setFileFilter(filter);
    chooser.setDialogTitle(MultiLanguages.getProperties("dialog.save.title"));
    System.out.println("[SaveLoad] - setChooserForSaveAs Fin");
  }

  private static boolean askOverwrite(File file)
  {
    int overwrite;
    /* Response :
     * -1 - Closed    -> Do nothing;
     * 0  - Yes / Ok  -> Save or Save as
     * 1  - No        -> Create a new Character
     */
    overwrite = ATKjOptionPane.showConfirmDialog(
        null,
        MultiLanguages.getProperties("dialog.overwriteFile.text").replaceAll("$1", file.getName()),
        MultiLanguages.getProperties("dialog.overwriteFile.title"),
        JOptionPane.YES_NO_OPTION, //Options : Yes No Cancel
        JOptionPane.QUESTION_MESSAGE,
        new ImageIcon(MultiLanguages.getProperties("dialog.overwriteFile.icon")) //icon
    );
    //If we are not allowed to overwrite the file ...
    if(overwrite != 0)
      //... then we do nothing
      return false;
    //... else (if the file not exist, or we can overwrite it) we save it
    return true;
  }

  /**
   * This function saves the Character and his equipment in the <i>File</i>
   * @param file - The file used to save the data.
   * @param character - The character to save.
   * @throws IOException
   */
  private static void saveIt(File file, Characters character) throws IOException
  {
    Equipment equipment = character.getEquipment();
    BufferedWriter fileWriter = new BufferedWriter(new FileWriter(file));
    EquipmentSlots[] slotList = {ArmorSlots.GLOVES, 
        ArmorSlots.JACKET, 
        ArmorSlots.PANTS,
        ArmorSlots.PAULDRONS, 
        ArmorSlots.SHOES,
        AccessoriesSlots.BELT,
        AccessoriesSlots.EARRING_1,
        AccessoriesSlots.EARRING_2,
        AccessoriesSlots.HEAD,
        AccessoriesSlots.RING_1,
        AccessoriesSlots.RING_2,
        HandsSlots.MAIN_HAND,
        HandsSlots.OFF_HAND};
    fileWriter.write("<?xml version=\"1.0\"?>"+"\n");
    fileWriter.write("<!DOCTYPE AionCharacter SYSTEM \"file:config/dtd/FileConfig.dtd\">\n");
    fileWriter.write("<AionCharacter>"+"\n");
    fileWriter.write("\t<Name>"+character.getName()+"</Name>"+"\n");
    fileWriter.write("\t<Level>"+character.getLevel()+"</Level>"+"\n");
    fileWriter.write("\t<Classe>"+character.getClasse().getId()+"</Classe>"+"\n");
    fileWriter.write("\t<Faction>"+character.getFaction().getId()+"</Faction>"+"\n");
    //Equipment
    fileWriter.write("\t<Equipment>"+"\n");
    for(EquipmentSlots slot : slotList)
    {
      Items item = equipment.getItem(slot);
      //If the item is null ...
      if(item == null)
        //... we just register -1 as itemId
        fileWriter.write("\t\t<Item itemClass=\"\" slotClass=\""+slot.getClass().getName()
            +"\" slotName=\""+slot+"\">-1</Item>\n");
      else
        fileWriter.write("\t\t<Item itemClass=\""+item.getClass().getName()+"\" slotClass=\""+slot.getClass().getName()
            +"\" slotName=\""+slot+"\">"+equipment.getID(slot)+"</Item>\n");
    }
    fileWriter.write("\t</Equipment>"+"\n");
    //Manastones
    fileWriter.write("</AionCharacter>");
    fileWriter.close();
    System.out.println("Save Ok");
  }

  public static void Load(ATKcontroller controller) throws IOException
  {
    int returnVal;
    File file;
    Characters newChar;
    setChooserForLoad();
    returnVal = chooser.showOpenDialog(null);
    /*
     * Return val :
     * 0 - Save
     * 1 - Cancel/Closex
     */
    if(returnVal == 1)
      return;//do nothing and quit
    file = chooser.getSelectedFile();

    newChar = loadIt(file);

    controller.getModel().setDirty(false);
    controller.getModel().setFileName(file.getName());
    controller.getModel().setFilePath(file.getPath());
    controller.notifyCharacterChanged(newChar);

 }

  private static Characters loadIt(File file) {
    try {
      //Objects required to read the XML file
      SAXBuilder saxBuilder = new SAXBuilder(true);
      /** Load the file **/
      Document docXML = saxBuilder.build(file);
      /** Get the root element **/
      Element root = docXML.getRootElement();

      new Equipment();

      /**Now we treat the file **/
      //Step 1 - Update Character info
      Characters newCharacter = loadCharacter(root);

      //Step 2 - Update the Equipment
      Equipment newEquipment = loadEquipment(root.getChild("Equipment"),
          newCharacter);
      newCharacter.setEquipment(newEquipment);

      return newCharacter;
    } catch (JDOMException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return null;
  }
  private static Equipment loadEquipment(Element equipmentRoot, Characters newCharacter) {
    String itemClassName, itemId, itemSlot, slotClassName;
    Equipment equipment = new Equipment();
    equipment.setCharacter(newCharacter);
    List<Element> itemList = equipmentRoot.getChildren();
    for(Element item : itemList)
    {
      itemClassName = item.getAttributeValue("itemClass");
      slotClassName = item.getAttributeValue("slotClass");
      itemSlot = item.getAttributeValue("slotName");
      EquipmentSlots slot;
      Items tmpItem;
      try {
        System.out.println("[SaveLoad] - Chargement de l'equipement - Slot : "+slotClassName);
        slot = (EquipmentSlots) Class.forName(slotClassName).getEnumConstants()[0];
        slot = slot.getSlot(itemSlot);

        itemId = item.getText();
        if(itemClassName.equalsIgnoreCase(""))
          tmpItem = null;
        else
          tmpItem = generateItem(itemClassName, itemId);
        equipment.addEquipment(tmpItem, slot);

      }catch (ClassNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
      } catch (CanNotEquipThisItem e1) {
        System.out.println("Erreur lors du chargement de l'équipement avec l'item ");
        e1.printStackTrace();
      }
    }
    return equipment;
  }

  private static Characters loadCharacter(Element aionCharacter)
  {
    String value;
    Characters newCharacter = new Characters();
    newCharacter.setName(aionCharacter.getChildText("Name")); //Name
    //Level
    value = aionCharacter.getChildText("Level");
    newCharacter.setLevel(Integer.valueOf(value));//Lvl
    //Classe
    value = aionCharacter.getChildText("Classe");
    newCharacter.setClasse(RpgBuilder.getClasseFromId(value));
    //Faction
    value = aionCharacter.getChildText("Faction");
    newCharacter.setFaction(RpgBuilder.getFactionFromId(value));

    return newCharacter;
  }
  private static Items generateItem(String itemClass,
                                    String itemId)
  {
    Items items = null;
    try {
      items = (Items) Class.forName(itemClass).newInstance();
      items.init(itemId);
    } catch (InstantiationException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return items;
  }
  private static void setChooserForLoad()
  {
    ATKfileFilter filter = new ATKfileFilter();
    filter.addSuffixe(".atk");
    filter.setDescription("dialog.fileFormat.text");

    chooser = new JFileChooser();
    chooser.setMultiSelectionEnabled(false);
    chooser.setDialogType(JFileChooser.OPEN_DIALOG);
    chooser.setDialogTitle(MultiLanguages.getProperties("dialog.load.title"));
    chooser.setFileFilter(filter);
    chooser.setDialogTitle(MultiLanguages.getProperties("dialog.save.title"));
  }
}
